const WebSocket = require('ws');
const http = require('http');
const express = require('express');
const cors = require('cors');
const mqtt = require('mqtt');
const { accessLog, errorLog } = require('./logger.js');

// WebSocket转发服务端口
const WS_FORWARDER_PORT = 8090;
// MQTT服务器配置
const MQTT_BROKER_URL = process.env.MQTT_BROKER_URL || 'mqtt://192.168.10.28'; // MQTT代理服务器地址
const MQTT_TOPIC = process.env.MQTT_TOPIC || 'v1/devices/me/telemetry'; // 遥测数据发布的主题
// 存储前端连接和对应的MQTT客户端映射
const clientMap = new Map(); // { frontendWs: { mqttClient, username } }
// 存储用户名到MQTT客户端的映射，便于重用连接
const usernameToClientMap = new Map(); // { username: mqttClient }

module.exports = () => {
  // 创建一个独立的Express应用和HTTP服务器
  const app = express();
  const server = http.createServer(app);
  
  // 配置CORS
  app.use(cors({ origin: '*' }));
  
  // 添加一个简单的状态检查接口
  app.get('/status', (req, res) => {
    res.json({
      status: 'running',
      port: WS_FORWARDER_PORT,
      connections: clientMap.size,
      uniqueUsers: usernameToClientMap.size
    });
  });
  
  // 创建独立的WebSocket服务器
  const wss = new WebSocket.Server({ server });
  
  // 为指定用户名获取或创建MQTT客户端
  function getOrCreateMqttClient(username, frontendWs) {
    // 检查是否已存在该用户名的MQTT客户端
    if (usernameToClientMap.has(username)) {
      const existingClient = usernameToClientMap.get(username);
      accessLog(`复用用户 ${username} 的现有MQTT连接`);
      return existingClient;
    }
    
    // 创建新的MQTT客户端连接
    const mqttOptions = {
      clientId: `${username}-${Date.now()}`,
      keepalive: 60,
      connectTimeout: 30000,
      // 使用用户名进行身份验证，密码固定为空
      username: username,
      password: '',
      // 启用自动重连
      reconnectPeriod: 1000
    };
    
    const mqttClient = mqtt.connect(MQTT_BROKER_URL, mqttOptions);
    
    // 处理MQTT连接成功
    mqttClient.on('connect', () => {
      accessLog(`用户 ${username} 已连接到MQTT服务器`);
      
      // 订阅MQTT主题，以便接收后台返回的数据
      mqttClient.subscribe(MQTT_TOPIC, (err) => {
        if (!err) {
          // accessLog(`用户 ${username} 已订阅MQTT主题: ${MQTT_TOPIC}`);
          console.log(`用户 ${username} 已订阅MQTT主题: ${MQTT_TOPIC}`);
        } else {
          errorLog(`用户 ${username} 订阅MQTT主题失败: ${err.message}`);
        }
      });
    });
    
    // 处理MQTT连接错误
    mqttClient.on('error', (error) => {
      // 记录更详细的错误信息
      const errorMsg = error.code ? `MQTT连接错误 [${error.code}]: ${error.message}` : `MQTT连接错误: ${error.message || error}`;
      errorLog(`用户 ${username} ${errorMsg}`);
    });
    
    // 订阅MQTT主题，接收后台可能返回的数据
    mqttClient.on('message', (topic, message) => {
      try {
        // 向前端转发从MQTT收到的消息
        if (frontendWs && frontendWs.readyState === WebSocket.OPEN) {
          frontendWs.send(JSON.stringify({
            type: 'mqtt_message',
            username: username,
            topic: topic,
            data: message.toString('utf8')
          }));
        }
        
        // 也向其他使用相同用户名的WebSocket连接发送消息
        clientMap.forEach((clientInfo, ws) => {
          if (ws !== frontendWs && ws.readyState === WebSocket.OPEN && clientInfo.username === username) {
            ws.send(JSON.stringify({
              type: 'mqtt_message',
              username: username,
              topic: topic,
              data: message.toString('utf8')
            }));
          }
        });
        
        accessLog(`从MQTT主题 ${topic} 接收数据并转发到用户 ${username}`);
      } catch (error) {
        errorLog(`转发MQTT消息到用户 ${username} 时出错:`, error);
      }
    });
    
    // 处理MQTT连接断开
    mqttClient.on('close', () => {
      accessLog(`用户 ${username} 的MQTT服务器连接已断开`);
      // 移除映射
      usernameToClientMap.delete(username);
      
      // 通知所有使用该用户名的WebSocket连接
      clientMap.forEach((clientInfo, ws) => {
        if (ws.readyState === WebSocket.OPEN && clientInfo.username === username) {
          ws.send(JSON.stringify({
            type: 'connection_status',
            username: username,
            status: 'disconnected',
            message: '与MQTT服务器的连接已断开'
          }));
        }
      });
    });
    
    // MQTT重连事件
    mqttClient.on('reconnect', () => {
      accessLog(`用户 ${username} 正在重新连接MQTT服务器`);
      // 通知所有使用该用户名的WebSocket连接
      clientMap.forEach((clientInfo, ws) => {
        if (ws.readyState === WebSocket.OPEN && clientInfo.username === username) {
          ws.send(JSON.stringify({
            type: 'connection_status',
            username: username,
            status: 'reconnecting',
            message: '正在重新连接MQTT服务器'
          }));
        }
      });
    });
    
    // 存储映射
    usernameToClientMap.set(username, mqttClient);
    return mqttClient;
  }
  
  wss.on('connection', (frontendWs, req) => {
    accessLog('前端客户端已连接到转发服务');
    console.log('前端客户端已连接到转发服务');
    
    // 初始化为未关联用户名状态
    clientMap.set(frontendWs, { mqttClient: null, username: null });
    
    // 处理前端消息，通过MQTT发布到后台
    frontendWs.on('message', (message) => {
      try {
        // 检查消息是否为Buffer，如果是则转换为字符串
        const messageStr = Buffer.isBuffer(message) ? message.toString('utf8') : message;
        
        // 尝试解析JSON消息
        let parsedMessage;
        try {
          parsedMessage = JSON.parse(messageStr);
        } catch (e) {
          // 如果不是有效的JSON，则向前端发送错误
          frontendWs.send(JSON.stringify({
            type: 'error',
            message: '消息格式无效，请发送有效的JSON格式'
          }));
          return;
        }
        
        // 检查消息是否包含用户名
        if (!parsedMessage.username) {
          frontendWs.send(JSON.stringify({
            type: 'error',
            message: '消息必须包含username字段'
          }));
          return;
        }
        
        const username = parsedMessage.username;
        const currentClientInfo = clientMap.get(frontendWs);
        
        // 如果用户名变更或首次设置用户名，获取/创建对应的MQTT客户端
        if (!currentClientInfo.username || currentClientInfo.username !== username) {
          // 获取或创建MQTT客户端
          const mqttClient = getOrCreateMqttClient(username, frontendWs);
          
          // 更新映射
          clientMap.set(frontendWs, { mqttClient: mqttClient, username: username });
          
          // 向前端发送连接状态
          frontendWs.send(JSON.stringify({
            type: 'connection_status',
            username: username,
            status: mqttClient.connected ? 'connected' : 'connecting',
            message: mqttClient.connected ? '已连接到MQTT服务器' : '正在连接MQTT服务器'
          }));
        }
        
        // 获取当前MQTT客户端
        const { mqttClient } = clientMap.get(frontendWs);
        
        // 发送消息到MQTT服务器
        if (mqttClient && mqttClient.connected) {
          // 核心处理：确保payload中的字段作为顶级字段发送，而不是嵌套对象
          let finalPayload = {};
          
          // 检查是否存在payload对象且为有效的非空对象
          if (parsedMessage.payload && typeof parsedMessage.payload === 'object' && parsedMessage.payload !== null) {
            // 直接赋值payload对象的内容，确保字段是顶级字段
            finalPayload = parsedMessage.payload;
            // accessLog(`用户 ${username} 提取payload中的字段作为顶级字段: ${Object.keys(finalPayload).join(', ')}`);
            // console.log(`用户 ${username} 提取payload中的字段作为顶级字段: ${Object.keys(finalPayload).join(', ')}`);
          } else {
            // 如果没有payload对象，则使用移除username后的所有字段
            const { username: _, ...payloadFields } = parsedMessage;
            finalPayload = payloadFields;
            // accessLog(`用户 ${username} 使用根级别的所有字段: ${Object.keys(finalPayload).join(', ')}`);
            // console.log(`用户 ${username} 使用根级别的所有字段: ${Object.keys(finalPayload).join(', ')}`);
          }
          
          // 确保finalPayload是一个有效的对象
          if (typeof finalPayload !== 'object' || finalPayload === null) {
            finalPayload = { data: finalPayload };
            accessLog(`用户 ${username} 数据不是对象，已包装为对象`);
          }
          
          // 转换为JSON字符串并发送
          const payloadStr = JSON.stringify(finalPayload);
          // console.log(`用户 ${username} 最终发送到MQTT的数据结构: ${payloadStr}`);
          mqttClient.publish(MQTT_TOPIC, payloadStr);
          accessLog(`用户 ${username} 的遥测数据已成功发布`);
          
          // 向前端确认消息已成功发布
          frontendWs.send(JSON.stringify({
            type: 'publish_ack',
            username: username,
            status: 'success',
            message: '遥测数据已成功发布'
          }));
        } else {
          errorLog(`用户 ${username} 的MQTT客户端未连接，无法发布消息`);
          frontendWs.send(JSON.stringify({
            type: 'error',
            username: username,
            message: 'MQTT连接未就绪，请稍后再试'
          }));
        }
      } catch (error) {
        errorLog('处理消息时出错:', error);
        if (frontendWs.readyState === WebSocket.OPEN) {
          frontendWs.send(JSON.stringify({
            type: 'error',
            message: '处理消息时发生错误'
          }));
        }
      }
    });
    
    // 处理前端连接关闭
    frontendWs.on('close', () => {
      const clientInfo = clientMap.get(frontendWs);
      if (clientInfo && clientInfo.username) {
        accessLog(`用户 ${clientInfo.username} 的前端客户端已断开连接`);
      } else {
        accessLog('未关联用户名的前端客户端已断开连接');
      }
      
      // 移除映射
      clientMap.delete(frontendWs);
      
      // 检查是否还有其他WebSocket连接使用该用户名的MQTT客户端
      // 如果没有，则关闭MQTT连接以节省资源
      if (clientInfo && clientInfo.username && clientInfo.mqttClient) {
        let hasOtherConnections = false;
        clientMap.forEach((info, ws) => {
          if (info.username === clientInfo.username) {
            hasOtherConnections = true;
          }
        });
        
        if (!hasOtherConnections) {
          accessLog(`没有其他连接使用用户 ${clientInfo.username} 的MQTT客户端，关闭连接`);
          clientInfo.mqttClient.end();
          usernameToClientMap.delete(clientInfo.username);
        }
      }
    });
    
    // 处理前端错误
    frontendWs.on('error', (error) => {
      errorLog('前端WebSocket错误:', error);
    });
  });
  
  // 定期检查并清理死连接
  setInterval(() => {
    clientMap.forEach((clientInfo, frontendWs) => {
      if (frontendWs.readyState === WebSocket.CLOSED) {
        // 移除映射
        clientMap.delete(frontendWs);
        
        // 检查是否需要关闭MQTT连接
        if (clientInfo.username && clientInfo.mqttClient) {
          let hasOtherConnections = false;
          clientMap.forEach((info, ws) => {
            if (info.username === clientInfo.username) {
              hasOtherConnections = true;
            }
          });
          
          if (!hasOtherConnections) {
            clientInfo.mqttClient.end();
            usernameToClientMap.delete(clientInfo.username);
          }
        }
      }
    });
    
    // 也检查用户名映射中的断开连接
    usernameToClientMap.forEach((mqttClient, username) => {
      if (!mqttClient.connected) {
        let hasActiveConnections = false;
        clientMap.forEach((info, ws) => {
          if (info.username === username && ws.readyState === WebSocket.OPEN) {
            hasActiveConnections = true;
          }
        });
        
        // 如果没有活跃的WebSocket连接，但MQTT客户端已断开，则清理
        if (!hasActiveConnections && !mqttClient.connected) {
          usernameToClientMap.delete(username);
        }
      }
    });
  }, 30000); // 每30秒检查一次
  
  // 启动独立的服务器
  server.listen(WS_FORWARDER_PORT, () => {
    accessLog(`WebSocket转发服务已启动，运行在端口 ${WS_FORWARDER_PORT}`);
  });
  
  // 返回服务器实例，便于管理
  return server;
};